// copyright (c) 2021 HUANG WEI QIANG
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/unistd.h>

#include "esp_err.h"
#include "esp_log.h"

#include "esp_http_server.h"
#include "d700_modbus.h"

static const char *TAG = "file_server";
static uint16_t param_num;
static uint8_t slave_addr;
static uint16_t input_value;
static uint16_t data_value;
/* Send HTTP response with a run-time generated html consisting of
 * a list of all files and folders under the requested path.
 * In case of SPIFFS this returns empty list when path is any
 * string other than '/', since SPIFFS doesn't support directories */
static esp_err_t http_home_page_hdr(httpd_req_t *req)
{
    extern const unsigned char d700_project_html_start[] asm("_binary_d700_project_html_start");
    extern const unsigned char d700_project_html_end[]   asm("_binary_d700_project_html_end");
    const size_t d700_project_size = ( d700_project_html_end - d700_project_html_start);
    extern const unsigned char d700_project_2nd_html_start[] asm("_binary_d700_project_2nd_html_start");
    extern const unsigned char d700_project_2nd_html_end[] asm("_binary_d700_project_2nd_html_end");
    const size_t d700_project_2nd_size = (d700_project_2nd_html_end - d700_project_2nd_html_start);
    extern const unsigned char d700_json_start[] asm("_binary_d700_json_start");
    extern const unsigned char d700_json_end[] asm("_binary_d700_json_end");
    const size_t d700_json_size = ( d700_json_end - d700_json_start);
    /* Add file upload form and script which on execution sends a POST request to /upload */
    httpd_resp_send_chunk(req, (const char *)d700_project_html_start,d700_project_size);
    httpd_resp_send_chunk(req,(const char*)d700_json_start,d700_json_size);
    httpd_resp_send_chunk(req,(const char*)d700_project_2nd_html_start,d700_project_2nd_size);
    /* Send empty chunk to signal HTTP response completion */
    httpd_resp_sendstr_chunk(req, NULL);
    printf("HTTP_GET method function had been called.\n");
    return ESP_OK;
}

static esp_err_t http_set_hdr(httpd_req_t *req){
    char buf[100];
    char num[16];
    char resp_str[20];
    int content_len = req->content_len;
    /* Read the data for the request */
    httpd_req_recv(req, buf, MIN(content_len, sizeof(buf)));
    printf("%s\n",buf);
    char* ret;

    ret=strstr(buf,"param_num") + 1;
    if(ret==NULL){
        printf("can not find the 'param_num' string");
        httpd_resp_send(req,"can not find the special string",HTTPD_RESP_USE_STRLEN);
        return ESP_FAIL;
    }
    ret += strlen("param_num");
    for(int i=0;i<16;i++){
        if(isdigit(*ret)) {
            num[i] = *ret;
            ret++;
        }
        else {
            num[i]='\0';
            break;}
    }
    param_num = (uint16_t)atoi(num);
    printf("SETTING: got the param_num is %d.\n",param_num);
    
    ret=strstr(buf,"slave_addr") + 1;
    if(ret==NULL){
        printf("can not find the 'slave_addr' string");
        httpd_resp_send(req,"can not find the special string",HTTPD_RESP_USE_STRLEN);
        return ESP_FAIL;
    }
    ret += strlen("slave_addr");
    for(int i=0;i<16;i++){
        if(isdigit(*ret)) {
            num[i] = *ret;
            ret++;
        }
        else {
            num[i]='\0';
            break;}
    }
    slave_addr = (uint8_t)atoi(num);
    printf("SETTING: got the slave_addr is %d\n",slave_addr);

    ret=strstr(buf,"input_value") + 1;
    if(ret==NULL){
        printf("can not find the 'input_value' string");
        httpd_resp_send(req,"can not find the special string",HTTPD_RESP_USE_STRLEN);
        return ESP_FAIL;
    }
    ret += strlen("input_value");
    for(int i=0;i<16;i++){
        if(isdigit(*ret)) {
            num[i] = *ret;
            ret++;
        }
        else {
            num[i]='\0';
            break;}
    }
    input_value = (uint16_t)atoi(num);
    printf("SETTING: got the input_value is %d\n",input_value);
    if(param_num<=1000){
        d700_modbus_set_param(slave_addr, param_num, input_value, 0); //write only one parameter
        d700_modbus_read_param(slave_addr, param_num, &data_value, 0,1); //read only one parameter
    }else{ 
        d700_modbus_set_param(slave_addr, param_num, input_value, param_num); //write only one parameter
        d700_modbus_read_param(slave_addr, param_num, &data_value, param_num,1); //read only one parameter
    }
    itoa((int)data_value,resp_str,10);
    httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
    return ESP_OK;
}

static esp_err_t http_read_hdr(httpd_req_t *req){
    printf("http_read_hdr() had been executed!\n");
    char buf[100];
    char num[16];
    char resp_str[20];
    int content_len = req->content_len;
    /* Read the data for the request */
    httpd_req_recv(req, buf,MIN(content_len,sizeof(buf)));
    printf("%s\n",buf);
    printf("read from html success.\n");

    char* ret;
    ret=strstr(buf,"param_num") + 1;
    if(ret==NULL){
        printf("can not find the 'param_num' string");
        httpd_resp_send(req,"can not find the special string",HTTPD_RESP_USE_STRLEN);
    }
    ret += strlen("param_num");
    for(int i=0;i<16;i++){
        if(isdigit(*ret)) {
            num[i] = *ret;
            ret++;
        }
        else {
            num[i]='\0';
            break;}
    }
    param_num = (uint16_t)atoi(num);
    printf("got the param_num is %d.\n",param_num);
    ret=strstr(buf,"slave_addr") + 1;
    if(ret==NULL){
        printf("can not find the 'slave_addr' string");
        httpd_resp_send(req,"can not find the special string",HTTPD_RESP_USE_STRLEN);
    }
    ret += strlen("slave_addr");
    for(int i=0;i<16;i++){
        if(isdigit(*ret)) {
            num[i] = *ret;
            ret++;
        }
        else {
            num[i]='\0';
            break;}
    }
    slave_addr = (uint8_t)atoi(num);
    printf("got the slave_addr is %d\n",slave_addr);

    if(param_num <= 1000)
    d700_modbus_read_param(slave_addr, param_num, &data_value, 0,1);
    else d700_modbus_read_param(slave_addr, param_num, &data_value, param_num,1); //read only one parameter
    printf("got the param_value from machine is %d\n",data_value);
    itoa((int)data_value,resp_str,10);

    httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
    return ESP_OK;
}

/* Function to start the file server */
esp_err_t start_file_server(){
    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();

    /* Use the URI wildcard matching function in order to
     * allow the same handler to respond to multiple different
     * target URIs which match the wildcard scheme */
    config.uri_match_fn = httpd_uri_match_wildcard;

    ESP_LOGI(TAG, "Starting HTTP Server");
    if (httpd_start(&server, &config) != ESP_OK) {
        ESP_LOGE(TAG, "Failed to start file server!");
        return ESP_FAIL;
    }

    /* URI handler for getting uploaded files */
    httpd_uri_t home_page = {
        .uri       = "/*",  // Match all URIs of type /path/to/file
        .method    = HTTP_GET,
        .handler   = http_home_page_hdr,
        .user_ctx  = NULL    // Pass server data as context
    };
    httpd_register_uri_handler(server, &home_page);

    httpd_uri_t set = {
        .uri       = "/set*",  // Match all URIs of type /path/to/file
        .method    = HTTP_POST,
        .handler   = http_set_hdr,
        .user_ctx  = NULL    // Pass server data as context
    };
    httpd_register_uri_handler(server, &set);

    httpd_uri_t read = {
        .uri       = "/read*",  // Match all URIs of type /path/to/file
        .method    = HTTP_POST,
        .handler   = http_read_hdr,
        .user_ctx  = NULL    // Pass server data as context
    };
    httpd_register_uri_handler(server, &read);


    return ESP_OK;
}
